<?php
/***
 * Candy框架 字符串加解密类
 * 
 * $Author: 刘森 (fingerboy@qq.com) $
 * $Date: 2019-08-05 23:39:50 $   
 */

declare(strict_types=1);
namespace Candy\Extend\Str;

defined('CANDY') OR die('You Are A Bad Guy. o_O???');

final Class Mcrypt {
	public static $defaultKey = 'c,n=X!OjvpiBbw(QC0ma';
	
	/**
	 * 字符加密解密
	 * 
	 * @param string $string 原文或密文
	 * @param string $key 密钥
	 * @param int $expiry 密文有效期,单位s,0 为永久有效
	 * @param string $type 处理类型  en 加密 de 解密
	 * @return string 经过 base64_encode 处理后的密文或原文
	 */
	public static function code(string $string,string $key = '',string $type = 'en',int $expiry = 0): string
	{
		$ckeyLength = 4;
		$key = md5($key ? $key : self::$defaultKey); //解密密匙
		$keya = md5(substr($key, 0, 16));		 //做数据完整性验证  
		$keyb = md5(substr($key, 16, 16));		 //用于变化生成的密文 (初始化向量IV)
		$keyc = $type == 'en' ? substr(md5(microtime()), - $ckeyLength) : substr($string, 0, $ckeyLength);
		$cryptkey = $keya . md5($keya . $keyc); 
		$keyLength = strlen($cryptkey);
		$string = $type == 'en' ? (sprintf('%010d', $expiry ? $expiry + time() : 0) . substr(md5($string . $keyb), 0, 16) . $string) : base64_decode(substr(str_replace(['-', '_', '.'], ['+', '/', '='], $string), $ckeyLength));
		$stringLength = strlen($string);
		$rndkey = [];	
		for($i = 0; $i <= 255; $i++){	
			$rndkey[$i] = ord($cryptkey[$i % $keyLength]);
		}

		$box = range(0, 255);	
		// 打乱密匙簿，增加随机性
		for($j = $i = 0; $i < 256; $i++){
			$j = ($j + $box[$i] + $rndkey[$i]) % 256;
			$tmp = $box[$i];
			$box[$i] = $box[$j];
			$box[$j] = $tmp;
		}	
		// 加解密，从密匙簿得出密匙进行异或，再转成字符
		$result = '';
		for($a = $j = $i = 0; $i < $stringLength; $i++){
			$a = ($a + 1) % 256;
			$j = ($j + $box[$a]) % 256;
			$tmp = $box[$a];
			$box[$a] = $box[$j];
			$box[$j] = $tmp; 
			$result .= chr(ord($string[$i]) ^ ($box[($box[$a] + $box[$j]) % 256]));
		}
		
		if($type == 'en'){
			$res = str_replace(['+', '/', '='], ['-', '_', '.'], $keyc . str_replace('=', '', base64_encode($result)));;
		}else{
			$res = '';
			if ((substr($result, 0, 10) == 0 || (int)substr($result, 0, 10) - time() > 0)
			&& substr($result, 10, 16) == substr(md5(substr($result, 26) . $keyb), 0, 16)
			){
				$res = substr($result, 26);
			}
		}
		return $res;
	}
	
	/**
	 * 简单对称加密算法之加密解密
     * @param string $string
     * @param string $skey 加密key
     * @return mixed
     */
    public static function symmetry(string $string = '',string $key = '',string $type = 'en'): bool|string
	{
		$skey = empty($key) ? self::$defaultKey : $key; //密匙
		if($type == 'en'){
			$strArr = str_split(base64_encode($string));
			$strCount = count($strArr);
			foreach (str_split($skey) as $key => $value)
				$key < $strCount && $strArr[$key].=$value;
				
			return str_replace(['+', '/', '='], ['-', '_', '.'], join('', $strArr));
		}else{
			$strArr = str_split(str_replace(['-', '_', '.'], ['+', '/', '='], $string), 2);
			$strCount = count($strArr);
			foreach (str_split($skey) as $key => $value)
				$key <= $strCount  && isset($strArr[$key]) && $strArr[$key][1] === $value && $strArr[$key] = $strArr[$key][0];
				
			return base64_decode(join('', $strArr));
		}
    }
	
	/**
	 * DES加密解密函数
	 * 
	 * @param $key 密钥
	 * @param $text 字符串
	 */
	function des(string $string = '',string $key = '',string $type = 'en'): string
	{
		$key = empty($key) ? self::$defaultKey : $key; //密匙
		if($type == 'en'){
			return base64_encode(openssl_encrypt($string, 'AES-256-CBC', $key, OPENSSL_RAW_DATA));
		}else{
			return openssl_decrypt(base64_decode($string), 'AES-256-CBC', $key, OPENSSL_RAW_DATA);
		}
	} 
}
